package com.twu.biblioteca.menu;

import com.twu.biblioteca.Book;
import com.twu.biblioteca.Library;

import java.io.InputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Menu {
    private static final String INVALID_OPTION_MESSAGE = "Select a valid option!";
    private static final String UNAVAILABLE_BOOK_MESSAGE = "That book is not available.";
    private static final String SUCCESS_CHECKOUT_MESSAGE = "Thank you! Enjoy the book";
    private static final String ENTER_TITLE_MESSAGE = "Enter the Book Title Followed by 'Enter' (not case sensitive)";
    private static final String ENTER_AUTHOR_MESSAGE = "Enter the Book Author Followed by 'Enter' (not case sensitive)";
    private static final String ENTER_YEAR_MESSAGE = "Enter the Book Year Followed by 'Enter' e.g 2014";
    private static final String SUCCESS_RETURN_MESSAGE = "Thank you for returning the book.";
    private static final String INVALID_BOOK_MESSAGE = "That is not a valid book to return.";
    private final Library library;
    private final PrintStream console;
    private final InputStream inputStream;
    private final Map<MenuOption, MenuAction> actions;


    public Menu(Library library, PrintStream console, InputStream inputStream) {
        this.library = library;
        this.console = console;
        this.inputStream = inputStream;

        actions = new HashMap<MenuOption, MenuAction>();
        actions.put(MenuOption.LIST_BOOK, new ListBooksAction());
        actions.put(MenuOption.CHECKOUT_BOOK, new CheckoutAction());
        actions.put(MenuOption.RETURN_BOOK, new ReturnAction());
        actions.put(MenuOption.QUIT, new QuitAction());
    }

    public void printOptions() {
        console.print(MenuOption.getOptionListAsString());
    }

    public MenuOption getOptionFromInput(String input) {
        for (MenuOption option : MenuOption.values()) {
            if (option.getKey().equalsIgnoreCase(input))
                return option;
        }
        console.println(INVALID_OPTION_MESSAGE);
        return null;
    }

    public void selectOption(MenuOption option) {
        String[] args = actions.get(option).readInput();
        actions.get(option).performAction(args);
    }


    private String[] readBookDetails() {
        Scanner scanner = new Scanner(inputStream);

        String[] args = new String[3];
        console.println(ENTER_TITLE_MESSAGE);
        args[0] = scanner.nextLine();
        console.println(ENTER_AUTHOR_MESSAGE);
        args[1] = scanner.nextLine();
        console.println(ENTER_YEAR_MESSAGE);
        args[2] = scanner.nextLine();
        return args;
    }

    /**
     * Inner Action Classes
     */

    private class ListBooksAction extends MenuAction {

        @Override
        public void performAction(String[] args) {
            console.print(library.getBookListAsString());
        }
    }

    private class QuitAction extends MenuAction {

        @Override
        public void performAction(String[] args) {
            console.println("Goodbye");
            System.exit(1);
        }
    }

    private class CheckoutAction extends MenuAction {

        @Override
        public String[] readInput() {
            return readBookDetails();
        }

        @Override
        public void performAction(String[] args) {

            for (Book book : library.getBooks()) {
                if (book.compareWithDetails(args[0], args[1], args[2])) {
                    book.setCheckedOut(true);
                    console.println(SUCCESS_CHECKOUT_MESSAGE);
                    return;   //Don't Checkout all copies, just one
                }
            }
            console.println(UNAVAILABLE_BOOK_MESSAGE);
        }
    }

    private class ReturnAction extends MenuAction {

        @Override
        public String[] readInput() {
            return readBookDetails();
        }

        @Override
        public void performAction(String[] args) {
            for (Book book : library.getBooks()) {
                if (book.compareWithDetails(args[0], args[1], args[2])) {
                    book.setCheckedOut(false);
                    console.println(SUCCESS_RETURN_MESSAGE);
                    return;
                }
            }
            console.println(INVALID_BOOK_MESSAGE);
        }
    }
}
